package com.yykj.hospital.server.service.banci.impl;

import com.yykj.common.constant.CommonConstant;
import com.yykj.common.enums.BanCiType;
import com.yykj.common.util.GsonUtil;
import com.yykj.hospital.client.dto.DoctorDTO;
import com.yykj.hospital.server.dto.banci.doctor.client.DoctorAppointmentScheduling;
import com.yykj.hospital.server.dto.banci.doctor.client.DoctorOnlineScheduling;
import com.yykj.hospital.server.dto.banci.doctor.client.DoctorTimeAppointment;
import com.yykj.hospital.server.dto.banci.doctor.client.DoctorTimeOnline;
import com.yykj.hospital.server.form.BanCiSearchForm;
import com.yykj.hospital.server.model.entity.HospitalDoctor;
import com.yykj.hospital.server.model.entity.banci.HospitalBanCi;
import com.yykj.hospital.server.model.entity.banci.HospitalDoctorBanCi;
import com.yykj.hospital.server.model.repository.banci.HospitalBanCiRepository;
import com.yykj.hospital.server.service.HospitalDoctorService;
import com.yykj.hospital.server.service.banci.BanCiSearchService;
import com.yykj.hospital.server.service.banci.DoctorClientBanCiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

@Service
@Slf4j
public class DoctorClientBanCiServiceImpl implements DoctorClientBanCiService {
    @Override
    public List<DoctorAppointmentScheduling> listDoctorAppointmentScheduling(String doctorId, LocalDate sDay, LocalDate eDay) {
        DoctorDTO info = doctorService.info(doctorId);

        List<DoctorTimeAppointment> doctorTimeAppointmentList = new ArrayList<>();
        List<HospitalBanCi> hospitalBanCiList = hospitalBanCiRepository.findAllByHospitalIdAndStatusAndTypeOrderByStartTime(info.getHospitalId(), true, BanCiType.appointment);
        Map<LocalTime, DoctorTimeAppointment> timeMap = new HashMap<>();
        List<LocalTime> timeList = new ArrayList<>();
        for (HospitalBanCi banCi : hospitalBanCiList) {
            if (banCi.getSegment()) {
                int mins = banCi.getEndTime().getHour() * 60 + banCi.getEndTime().getMinute() - banCi.getStartTime().getHour() * 60 - banCi.getStartTime().getMinute();
                int duration = (banCi.getDuration() == null || banCi.getDuration() == 0) ? CommonConstant.DEFAULT_DURATION : banCi.getDuration();
                int cnt = mins / duration;
                LocalTime startTime = banCi.getStartTime();
                LocalTime endTime = startTime.plusMinutes(duration);
                for (int i = 0; i < cnt; i++) {
                    DoctorTimeAppointment defaultAppointment = new DoctorTimeAppointment();
                    defaultAppointment.setStartTime(startTime);
                    defaultAppointment.setEndTime(endTime);
                    doctorTimeAppointmentList.add(defaultAppointment);
                    timeMap.put(startTime, defaultAppointment);
                    timeList.add(startTime);

                    startTime = endTime;
                    endTime = startTime.plusMinutes(duration);

                }
                if (startTime.isBefore(banCi.getEndTime())) {
                    DoctorTimeAppointment defaultAppointment = new DoctorTimeAppointment();
                    defaultAppointment.setStartTime(startTime);
                    defaultAppointment.setEndTime(banCi.getEndTime());
                    doctorTimeAppointmentList.add(defaultAppointment);
                    timeMap.put(startTime, defaultAppointment);
                    timeList.add(startTime);
                }

            } else {
                DoctorTimeAppointment defaultAppointment = new DoctorTimeAppointment();
                defaultAppointment.setStartTime(banCi.getStartTime());
                defaultAppointment.setEndTime(banCi.getEndTime());
                doctorTimeAppointmentList.add(defaultAppointment);
                timeMap.put(banCi.getStartTime(), defaultAppointment);
                timeList.add(banCi.getStartTime());
            }
        }

        BanCiSearchForm form = BanCiSearchForm.builder()
                .hospitalId(info.getHospitalId())
                .depId(info.getDepId())
                .doctorId(doctorId)
                .baseTime(LocalDateTime.now())
                .type(BanCiType.appointment)
                .build();

        List<HospitalDoctorBanCi> doctorBanCiList = searchService.searchBanCi(form);

        Map<String, HospitalDoctorBanCi> doctorBanCiMap = new HashMap<>();
        Set<LocalDate> daySet = new HashSet<>();
        for (HospitalDoctorBanCi banCi : doctorBanCiList) {
            String key = banCi.getDay() + "_" + banCi.getStartTime();
            doctorBanCiMap.put(key, banCi);
            daySet.add(banCi.getDay());
        }

        List<DoctorAppointmentScheduling> result = new ArrayList<>();
        long day = eDay.toEpochDay() - sDay.toEpochDay();
        for (long i = 0; i <= day; i++) {
            LocalDate lDay = sDay.plusDays(i);
            if (daySet.contains(lDay)) {
                DoctorAppointmentScheduling scheduling = new DoctorAppointmentScheduling();
                scheduling.setDay(lDay);
                result.add(scheduling);
                for (LocalTime localTime : timeList) {
                    String key = lDay + "_" + localTime;
                    HospitalDoctorBanCi banCi = doctorBanCiMap.get(key);
                    if (banCi != null) {
                        DoctorTimeAppointment appointment = new DoctorTimeAppointment();
                        BeanUtils.copyProperties(banCi, appointment);
                        appointment.setRemain(banCi.getAppointment()-banCi.getAppointmentUsed());
                        appointment.setTotal(banCi.getAppointment());
                        scheduling.getList().add(appointment);
                    } else {
                        scheduling.getList().add(timeMap.get(localTime));
                    }
                }

            }else{
                DoctorAppointmentScheduling defaultAppointment = new DoctorAppointmentScheduling();
                defaultAppointment.setDay(lDay);
                defaultAppointment.setList(doctorTimeAppointmentList);
                result.add(defaultAppointment);
            }
        }


        return result;
    }

    @Override
    public List<DoctorOnlineScheduling> listDoctorOnlineScheduling(String doctorId, LocalDate sDay, LocalDate eDay) {
        DoctorDTO info = doctorService.info(doctorId);
        List<DoctorTimeOnline> doctorTimeOnline = new ArrayList<>();
        List<HospitalBanCi> hospitalBanCiList = hospitalBanCiRepository.findAllByHospitalIdAndStatusAndTypeOrderByStartTime(info.getHospitalId(), true, BanCiType.online);
        Map<LocalTime, DoctorTimeOnline> timeMap = new HashMap<>();
        List<LocalTime> timeList = new ArrayList<>();
        for (HospitalBanCi banCi : hospitalBanCiList) {
            if (banCi.getSegment()) {
                int mins = banCi.getEndTime().getHour() * 60 + banCi.getEndTime().getMinute() - banCi.getStartTime().getHour() * 60 - banCi.getStartTime().getMinute();
                int duration = (banCi.getDuration() == null || banCi.getDuration() == 0) ? CommonConstant.DEFAULT_DURATION : banCi.getDuration();
                int cnt = mins / duration;
                LocalTime startTime = banCi.getStartTime();
                LocalTime endTime = startTime.plusMinutes(duration);
                for (int i = 0; i < cnt; i++) {
                    DoctorTimeOnline defaultOnline = new DoctorTimeOnline();
                    defaultOnline.setStartTime(startTime);
                    defaultOnline.setEndTime(endTime);
                    doctorTimeOnline.add(defaultOnline);
                    timeMap.put(startTime, defaultOnline);
                    timeList.add(startTime);

                    startTime = endTime;
                    endTime = startTime.plusMinutes(duration);

                }
                if (startTime.isBefore(banCi.getEndTime())) {
                    DoctorTimeOnline defaultOnline = new DoctorTimeOnline();
                    defaultOnline.setStartTime(startTime);
                    defaultOnline.setEndTime(banCi.getEndTime());
                    doctorTimeOnline.add(defaultOnline);
                    timeMap.put(startTime, defaultOnline);
                    timeList.add(startTime);
                }

            } else {
                DoctorTimeOnline defaultOnline = new DoctorTimeOnline();
                defaultOnline.setStartTime(banCi.getStartTime());
                defaultOnline.setEndTime(banCi.getEndTime());
                doctorTimeOnline.add(defaultOnline);
                timeMap.put(banCi.getStartTime(), defaultOnline);
                timeList.add(banCi.getStartTime());
            }
        }

        BanCiSearchForm form = BanCiSearchForm.builder()
                .hospitalId(info.getHospitalId())
                .depId(info.getDepId())
                .doctorId(doctorId)
                .baseTime(LocalDateTime.now())
                .type(BanCiType.online)
                .build();

        List<HospitalDoctorBanCi> doctorBanCiList = searchService.searchBanCi(form);

        Map<String, HospitalDoctorBanCi> doctorBanCiMap = new HashMap<>();
        Set<LocalDate> daySet = new HashSet<>();
        for (HospitalDoctorBanCi banCi : doctorBanCiList) {
            String key = banCi.getDay() + "_" + banCi.getStartTime();
            doctorBanCiMap.put(key, banCi);
            daySet.add(banCi.getDay());
        }

        List<DoctorOnlineScheduling> result = new ArrayList<>();
        long day = eDay.toEpochDay() - sDay.toEpochDay();
        for (long i = 0; i <= day; i++) {
            LocalDate lDay = sDay.plusDays(i);
            if (daySet.contains(lDay)) {
                DoctorOnlineScheduling scheduling = new DoctorOnlineScheduling();
                scheduling.setDay(lDay);
                result.add(scheduling);
                for (LocalTime localTime : timeList) {
                    String key = lDay + "_" + localTime;
                    HospitalDoctorBanCi banCi = doctorBanCiMap.get(key);
                    if (banCi != null) {
                        DoctorTimeOnline online = new DoctorTimeOnline();
                        BeanUtils.copyProperties(banCi, online);
                        if(banCi.getPic()>banCi.getPicUsed()){
                            online.setPicAvailable(true);
                        }
                        if(banCi.getVoice()>banCi.getVoiceUsed()){
                            online.setVoiceAvailable(true);
                        }
                        if(banCi.getVideo()>banCi.getVideoUsed()){
                            online.setVideoAvailable(true);
                        }
                        scheduling.getList().add(online);
                    } else {
                        scheduling.getList().add(timeMap.get(localTime));
                    }
                }

            }else{
                DoctorOnlineScheduling defaultOnline = new DoctorOnlineScheduling();
                defaultOnline.setDay(lDay);
                defaultOnline.setList(doctorTimeOnline);
                result.add(defaultOnline);
            }
        }

        return result;

    }

    private HospitalDoctorService doctorService;
    private BanCiSearchService searchService;

    private HospitalBanCiRepository hospitalBanCiRepository;

    @Autowired
    public void setSearchService(BanCiSearchService searchService) {
        this.searchService = searchService;
    }

    @Autowired
    public void setHospitalBanCiRepository(HospitalBanCiRepository hospitalBanCiRepository) {
        this.hospitalBanCiRepository = hospitalBanCiRepository;
    }

    @Autowired
    public void setDoctorService(HospitalDoctorService doctorService) {
        this.doctorService = doctorService;
    }
}
